use std::{
    fmt::{self, Display, Formatter},
    str::FromStr,
};

#[derive(Debug)]
struct TestStruct {
    a: usize,
    b: String,
}

impl FromStr for TestStruct {
    type Err = anyhow::Error;

    fn from_str(data: &str) -> Result<TestStruct, Self::Err> {
        let data = data.trim_start_matches('{').trim_end_matches('}');
        let tokens = data.split(',');
        let tokens = tokens.collect::<Vec<&str>>();
        if tokens.len() != 2 {
            return Err(anyhow::anyhow!("TestStruct must have two fields"));
        }

        let a_mapping = tokens[0];
        let index = a_mapping.find(':');
        if index.is_none() {
            return Err(anyhow::anyhow!("Mapping of 'a' field does not have ':'"));
        }
        let index = index.unwrap();
        let a_mapping_val = a_mapping[index + 1..]
            .parse::<usize>()
            .map_err(|_| anyhow::anyhow!("Invalid value of 'a' field"))?;

        let b_mapping = tokens[1];
        let index = a_mapping.find(':');
        if index.is_none() {
            return Err(anyhow::anyhow!("Mapping of 'b' field does not have ':'"));
        }
        let index = index.unwrap();
        let b_mapping_val = &b_mapping[index + 1..];

        Ok(TestStruct {
            a: a_mapping_val,
            b: b_mapping_val.to_string(),
        })
    }
}

impl Display for TestStruct {
    fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
        write!(formatter, "{{a:{},b:{}}}", self.a, self.b)
    }
}

fn main() {
    let structure = TestStruct {
        a: 5,
        b: "hello".to_string(),
    };
    let structure_as_text = structure.to_string();
    println!("Our Test Struct as JSON: '{}'", structure_as_text);
    println!(
        "JSON to Our Test Struct: {:?}",
        TestStruct::from_str(&structure_as_text)
    );
}
